package cs236369.webserver;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Properties;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.SyncBasicHttpParams;
import org.apache.http.protocol.UriPatternMatcher;
import org.xml.sax.SAXException;

import cs236369.webserver.DTOs.HandlerMapping;
import cs236369.webserver.DTOs.MimeMapping;
import cs236369.webserver.DTOs.ServerConfigDTO;
import cs236369.webserver.dynamicLoad.HandlerLoader;
import cs236369.webserver.queue.managers.RequestTaskManager;
import cs236369.webserver.queue.managers.SocketTaskManager;
import cs236369.webserver.xml.XMLParser;

public class WebServer {
	private Collection<MimeMapping> mimes = null;
	private ServerConfigDTO serverConfig = null;
	private Collection<HandlerMapping> handlers = null;
	private SocketTaskManager socketListenertaskManager = null;
	private RequestTaskManager requestTaskManager = null;
	private UriPatternMatcher requestHandlerRegistry = null;
	
	//	private TaskManager<SocketHandler> ReqTaskManager = null;

	public WebServer(String config) throws Exception {
		parseXmlFile(config);
		setupRegistry();
	}

	public void init() throws IOException {
//		ReqTaskManager = new TaskManager<SocketHandler>(
//				serverConfig.getNumOfReqHandlerThreads());
		
		requestTaskManager = new RequestTaskManager(
				requestHandlerRegistry,
				serverConfig,
				mimes);
		
		socketListenertaskManager = new SocketTaskManager(
				serverConfig.getNumOfSocketThreads(),
				requestTaskManager,
				setHTTPParams());

	}

	private void setupRegistry() 
			throws SecurityException, IllegalAccessException, 
			NoSuchMethodException, ClassNotFoundException, 
			IllegalArgumentException, InstantiationException, 
			InvocationTargetException {
		
		requestHandlerRegistry = new UriPatternMatcher();
		
		for(HandlerMapping hm : handlers) {
			Properties p = new Properties();
			p.putAll(hm.getParameters());
			for (String extention : hm.getExtentions()) {
				requestHandlerRegistry.register("*"+extention,
						new HandlerLoader(hm.getHandlerClassName(),p)
						);
			}
		}
		
		requestHandlerRegistry.register("*", 
										new HandlerLoader(DefaultHandler.class.getName(), new Properties())
									   );
	}

	public void start() {
		try {
			RequestListenerThread requestListenerThread = new RequestListenerThread(
					serverConfig.getListeningPort(), setHTTPParams(),
					socketListenertaskManager);
			requestListenerThread.setDaemon(true);
			requestListenerThread.run();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	private HttpParams setHTTPParams() {
		HttpParams params = new SyncBasicHttpParams();
		params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 3000000)
				.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE,
						16 * 1024)
				.setBooleanParameter(
						CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
				.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
				.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HW4/1.1");
		return params;
	}

	public static void main(String[] args) throws Exception {
		WebServer srv = new WebServer("config.xml");
		srv.init();
		srv.start();
	}

	private void parseXmlFile(String xmlFile)
			throws ParserConfigurationException, SAXException, IOException {
		XMLParser xmlParse = new XMLParser();
		mimes = xmlParse.getMimesFromConfigXML(xmlFile);
//		for (MimeMapping m : mimes) {
//			System.out.println(m);
//		}
		serverConfig = xmlParse.getServerConfigDTO(xmlFile);
//		System.out.println(serverConfig);
		handlers = xmlParse.getHandlerAndExtentions(xmlFile);
//		for (HandlerMapping hm : handlers) {
//			System.out.print(hm);
//		}
		System.out.println("Done.");
	}
}
